package com.ndp.fb.rdb.mongo.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.AggregationOptions;
import com.mongodb.BasicDBObject;
import com.mongodb.Cursor;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.WriteConcern;
import com.ndp.fb.constant.MongoConstants;
import com.ndp.fb.model.business.vo.stats.AdResourceStatsQueryParam;
import com.ndp.fb.mongo.api.AdVideoMongoService;
import com.ndp.fb.mongo.api.IMongodbService;
import com.ndp.fb.mongo.model.AdvideoForMongo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by sisi.chen on 2016/1/15.
 */
@Service
public class AdVideoMongoServiceImpl implements AdVideoMongoService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private DB adResourceMongoDBClientPrimary;

    @Autowired
    private IMongodbService mongodbService;

    @Override
    public Map<String, Object> findByConditions(AdResourceStatsQueryParam adResourceStatsQueryParam) {
        //管道
        List<DBObject> pipeline = new ArrayList<>();
        BasicDBObject basicDBObject = getBasicQueryDBObject(adResourceStatsQueryParam);

        //过滤数据
        BasicDBObject matchDBObject1 = new BasicDBObject();
        matchDBObject1.put("$match", basicDBObject);
        pipeline.add(matchDBObject1);

        //排序
        List<Map<String, Integer>> sortList = adResourceStatsQueryParam.getSortList();
        sort(pipeline, sortList);

        //分组，计算统计行
        BasicDBObject groupChildObject = new BasicDBObject()
                .append("_id", null)
                .append("adVideoList", new BasicDBObject("$push", "$$CURRENT"))
                .append("totalCount", new BasicDBObject("$sum", 1));
        pipeline.add(new BasicDBObject("$group", groupChildObject));

        //分页
        BasicDBObject projectChildDBObject = new BasicDBObject()
                .append("summary", new BasicDBObject("totalCount", "$totalCount"));
        Integer page = adResourceStatsQueryParam.getPage();
        Integer pageSize = adResourceStatsQueryParam.getPageSize();
        if (null != page && 0 != page && null != pageSize && 0 != pageSize) {
            projectChildDBObject.put("adVideoList", new BasicDBObject("$slice", new Object[]{"$adVideoList", (page - 1) * pageSize, pageSize}));
        } else {
            projectChildDBObject.put("adVideoList", 1);
        }
        pipeline.add(new BasicDBObject("$project", projectChildDBObject));

        logger.info("Mongo查询语句:" + com.mongodb.util.JSON.serialize(pipeline));
        Long start = System.currentTimeMillis();
        AggregationOptions aggregationOptions = AggregationOptions.builder().allowDiskUse(true).build();
		Cursor cursor = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO).aggregate(pipeline, aggregationOptions);
        logger.info("Mongo聚合查询花费时间：" + (System.currentTimeMillis() - start) + "毫秒");
        Map<String, Object> result = null;
        try {
            if (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                result = JSONObject.parseObject(JSON.toJSONString(dbObject), Map.class);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            cursor.close();
        }
        logger.info("获取明细行耗时：" + (System.currentTimeMillis() - start));
        return result;
    }

    private void sort(List<DBObject> pipeline, List<Map<String, Integer>> sortList) {
        if (!CollectionUtils.isEmpty(sortList)) {
            BasicDBObject sortDBObject = new BasicDBObject();
            for (Map<String, Integer> sort : sortList) {
                Set<Map.Entry<String, Integer>> entries = sort.entrySet();
                for (Map.Entry<String, Integer> entry : entries) {
                    sortDBObject.put(entry.getKey(), entry.getValue());
                }
            }
            pipeline.add(new BasicDBObject("$sort", sortDBObject));
        }
    }

    private BasicDBObject getBasicQueryDBObject(AdResourceStatsQueryParam adResourceStatsQueryParam) {
        //过滤数据
        BasicDBObject basicDBObject = new BasicDBObject();

        //公司信息
        Long orgId = adResourceStatsQueryParam.getOrgId();
        if (null != orgId && 0 != orgId) {
            basicDBObject.put("orgId", orgId);
        }

        //用户信息
        Set<String> userIdSet = adResourceStatsQueryParam.getUserIdSet();
        if (!CollectionUtils.isEmpty(userIdSet)) {
            basicDBObject.put("userId", new BasicDBObject("$in", userIdSet));
        }

        //审核状态
        Integer reviewStatus = adResourceStatsQueryParam.getReviewStatus();
        if (reviewStatus != null) {
            basicDBObject.put("reviewStatus", reviewStatus);
        }

        //删除状态
        Integer isDelete = adResourceStatsQueryParam.getIsDelete();
        if (isDelete != null) {
            basicDBObject.put("isDelete", isDelete);
        }

        //内或外部美宣
        Integer from = adResourceStatsQueryParam.getFrom();
        if (from != null) {
            basicDBObject.put("from", from);
        }

        //按tag过滤
        Map<String, Set<Object>> tags = adResourceStatsQueryParam.getTags();
        if (!CollectionUtils.isEmpty(tags)) {
            for (Map.Entry<String, Set<Object>> tag : tags.entrySet()) {
                String key = tag.getKey();
                Set<Object> value = tag.getValue();
                basicDBObject.put("tags." + key, new BasicDBObject("$in", value));
            }
        }

        // ResourceType过滤
        String resourceType = adResourceStatsQueryParam.getResourceType();
        if (StringUtils.isNotEmpty(resourceType)) {
            basicDBObject.put("resourceType", resourceType);
        }
        return basicDBObject;
    }

    @Override
    public List<AdvideoForMongo> findByMd5(String md5) {
        DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject query = new BasicDBObject();
        query.put("md5", md5);
        Cursor cursor = collection.find(query);
        List<AdvideoForMongo> advideoForMongos = new ArrayList<>();
        convertMongoObj(cursor, advideoForMongos);
        return advideoForMongos;
    }

    @Override
    public AdvideoForMongo findByMd5AndOrgId(String md5, Long orgId) {
        DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject query = new BasicDBObject();
        query.put("md5", md5);
        query.put("orgId", orgId);
        DBObject dbObject = collection.findOne(query);
        if (dbObject == null) {
            return null;
        } else {
            //Mogo不能强转
            return JSONObject.parseObject(JSON.toJSONString(dbObject), AdvideoForMongo.class);
        }
    }

    @Override
    public void batchSave(List<AdvideoForMongo> advideoForMongos) {
    	 mongodbService.batchSaveOrUpdateWithoutHistory(adResourceMongoDBClientPrimary, MongoConstants.TABLE_NAME_ADVIDEO, JSONArray.toJSONString(advideoForMongos), new String[]{"mongodbId"}, false);
    }

    @Override
    public void update(String mongodbId, Map<String, Object> map) {
        DBObject query = new BasicDBObject("mongodbId", mongodbId);
        DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject updateObj = new BasicDBObject();
        for (Map.Entry<String, Object> stringObjectEntry : map.entrySet()) {
            String key = stringObjectEntry.getKey();
            Object value = stringObjectEntry.getValue();
            updateObj.put(key, value);
        }
        collection.update(query, new BasicDBObject("$set", updateObj), false, true,WriteConcern.JOURNALED);
    }

    @Override
    public void upateFbActVideoId(String md5, String fbAccountId, String fbvideoId) {
        DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject query = new BasicDBObject();
        query.put("md5", md5);
        DBObject update = new BasicDBObject();
        update.put("fbAccountId", fbAccountId);
        update.put("fbVideoId", fbvideoId);
        update.put("updatedTime", new Date());
        collection.update(query, new BasicDBObject("$addToSet", new BasicDBObject("uploadFbAccounts", update)), true, true,WriteConcern.JOURNALED);
    }

    @Override
    public AdvideoForMongo findByMongoId(String mongodId) {
        DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject query = new BasicDBObject();
        query.put("mongodbId", mongodId);
        DBObject dbObject = collection.findOne(query);
        if (dbObject == null) {
            return null;
        } else {
            //Mogo不能强转
            return JSONObject.parseObject(JSON.toJSONString(dbObject), AdvideoForMongo.class);
        }
    }

    @Override
    public List<AdvideoForMongo> findByMongoIds(List<String> mongodIds) {
        DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject query = new BasicDBObject();
        query.put("mongodbId", new BasicDBObject("$in", mongodIds));
        Cursor cursor = collection.find(query);

        List<AdvideoForMongo> advideoForMongos = new ArrayList<>();
        convertMongoObj(cursor, advideoForMongos);

        return advideoForMongos;
    }

    private void convertMongoObj(Cursor cursor, List<AdvideoForMongo> advideoForMongos) {
        try {
            AdvideoForMongo advideoForMongo;
            while (cursor.hasNext()) {
                DBObject dbObject = cursor.next();
                //Mogo不能强转
                advideoForMongo = JSONObject.parseObject(JSON.toJSONString(dbObject), AdvideoForMongo.class);
                advideoForMongos.add(advideoForMongo);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            cursor.close();
        }
    }

	@Override
	public AdvideoForMongo findByFbVideoId(String videoId) {
		DBCollection collection = adResourceMongoDBClientPrimary.getCollection(MongoConstants.TABLE_NAME_ADVIDEO);
        DBObject query = new BasicDBObject();
        query.put("uploadFbAccounts.fbVideoId", videoId);
        DBObject dbObject = collection.findOne(query);
        if (dbObject == null) {
            return null;
        } else {
            //Mogo不能强转
            return JSONObject.parseObject(JSON.toJSONString(dbObject), AdvideoForMongo.class);
        }
	}
}

